# -*- coding: utf-8 -*-

'''
Created on 31/01/2010

@author: Joger Quintero
'''
import wx
import os
import sys
import re
import time
from shutil import rmtree
from threading import Thread
    
from cifrar.modelo import Modelo
from comun import mensageError as msje, mensageAlerta as msja, mensajePregunta as msjp, validarNombreFichero, validarClave,verificarCorreo,dialogEntrada, mensageOkCancel as msjOk, getUrl

#Constante que permite almacenar un ID para el subproceso del 
# mensaje de barra de progreso
EVT_RESULT_ID = wx.NewId()

class Controlador():
    '''
    classdocs
    '''

    def __init__(self,vista):
        '''
        Constructor
        '''
        self.vista = vista
        #self.home = os.getenv("HOME")
        self.entrarEvento = True
        self.rutaTibisay = os.getenv('HOME') + '/.tibisay/'
        self.unidades = 'unidades'
        self.montaje = 'montaje'
        self.rutaGpg = self.rutaTibisay + 'gpg' #'/home/joger/.gnupg'
        self.modelo = Modelo(self)

        if not self.verificarExisteRuta():
            exit()
    
    ############BOTONES########################
    
    def eventoCifrar(self,evt):
        
        if not self.verificarArchivosEnDir(): return
            
        if not len(self.modelo.listarLaves(False)):
            msje(self.vista,"¡No existen llaves públicas para cifrar documentos!\n¡Debe crear o importar llaves púlicas para realizar el cifrado de documentos!") 
            return 
        
        url = getUrl(self.vista)
        #print url
        if not url: return
        if not msjOk(self.vista,u"Los archivos serán almacenados en: \n" + url + u"\n¿Está de acuerdo?"):
            return
                                
        fingerPrintC = self.vista.cifrarDatos(self.vista)
        if not fingerPrintC: return
        
        error=''
        #Obtenemos el total de elementos añadidos al TreeCtrl que contiene los ficheros
        totalItemsTreeCtrl = self.vista.dirAnhadido.GetItemCount()
        #Procedemos a recorrer los archivos
        for i in range(totalItemsTreeCtrl):
            #Obtenemos la dirección de cada item del TreeCtrl
            pathOrigen = self.vista.dirAnhadido.GetItem(i,1).GetText()
            #print pathOrigen
            #print "Archivos a procesar"
            
            listaArchivos = self.obtenerArchivosAProcesar(pathOrigen).split(",")[0:-1]
            error = False
            #Recorremos los archivos en contrados 
            for archivoProcesar in listaArchivos:
                
                #print archivoProcesar
                #continue
                f = open(archivoProcesar,'rb')
                data = f.read()
                f.close()
                data_procesada = self.cifrar(data,fingerPrintC)
                if not data_procesada:
                    msje(self.vista,"Ocurrio un error al momento de querer cifrar el documento:\n" + archivoProcesar)
                    error = True;
                    continue
            

                archivoCrear = self.obtenerArchivoACrear(archivoProcesar,pathOrigen,url)
                archivoCrear+= ".gpg"
                
                if os.path.isfile(archivoCrear):
                    if not msjp(self.vista,u"Ya existe el archivo:\n%s\n¿Desea sobrescribirlo?" % archivoCrear.encode('utf-8')):
                        continue
                    else:
                        os.remove(archivoCrear)   
                else:
                    try:
                        os.makedirs(os.path.dirname(archivoCrear))
                    except OSError:
                        pass
                
                f = open(archivoCrear,"wb")
                f.write(data_procesada)
                f.close()

        #Limpiamos el TreeCtrl y el formulario
        self.vista.dirTree.ReCreateTree()
        self.limpiarDatosForm()
        msj = u"¡Los datos fueron procesados!"
        if error:
            msj = u"¡Solo fueron procesados los datos donde no ocurió error!"
        
        msja(self.vista,msj)
            
        
    def eventoDescifrar(self,evt):
        
        if not self.verificarArchivosEnDir(): return
        
        if not len(self.modelo.listarLaves(True)):
            msje(self.vista,"¡No existen llaves privadas para descifrar documentos!\n¡Debe crear o importar llaves privadas para descifrar documentos!") 
            return

        url = getUrl(self.vista)
        if not url: return
        if not msjOk(self.vista,u"Los archivos serán almacenados en: \n" + url + u"\n¿Está de acuerdo?"):
            return
        
        clave = dialogEntrada(self.vista,"CLAVE PARA DESCIFRAR",True).encode('utf-8')
        if not clave: return
        
        error = False
        patron = re.compile("(\.gpg)$");
        
        #Obtenemos el total de elementos añadidos al TreeCtrl que contiene los ficheros
        totalItemsTreeCtrl = self.vista.dirAnhadido.GetItemCount()
        #Procedemos a recorrer los archivos
        for i in range(totalItemsTreeCtrl):
            #Obtenemos la dirección de cada item del TreeCtrl
            pathOrigen = self.vista.dirAnhadido.GetItem(i,1).GetText()
            listaArchivos = self.obtenerArchivosAProcesar(pathOrigen).split(",")[0:-1]
            
            #Recorremos los archivos en contrados 
            for archivoProcesar in listaArchivos:
                f = open(archivoProcesar,'rb')
                data = f.read()
                f.close()
                
                data_procesada = self.descifrar(data,clave).data
                if not data_procesada:
                    msje(self.vista,u"¡Error de descifrado!\n\n"
                                                    + u"Posibles causas:\n" 
                                                    + u"  1) No existe una llave privada para descifrar\n"
                                                    + u"  2) Ingreso de password incorrecto.\n\n"
                                                    + u"El fichero " + archivoProcesar + " no fue descifrado\n"
                                                    )
                    continue
                
                archivoCrear = self.obtenerArchivoACrear(archivoProcesar,pathOrigen,url)
                archivoCrear = patron.sub("",archivoCrear)
                
                #print archivoCrear
                #print "#########################"

                if os.path.isfile(archivoCrear):
                    if not msjp(self.vista,u"Ya existe el archivo:\n%s\n¿Desea sobrescribirlo?" % archivoCrear.encode('utf-8')):
                        continue
                    else:
                        os.remove(archivoCrear)   
                else:
                    try:
                        os.makedirs(os.path.dirname(archivoCrear))
                    except OSError:
                        pass
                
                
                f = open(archivoCrear,"wb")
                f.write(data_procesada)
                f.close()
    
                
        #Limpiamos el TreeCtrl y el formulario
        self.vista.dirTree.ReCreateTree()
        self.limpiarDatosForm()
        msj = u"¡Los datos fueron procesados!"
        if error:
            msj = u"¡Solo fueron procesados los datos donde no ocurió error!"
        
        msja(self.vista,msj)
        
    
    def eventoFirmar(self,evt):
        
        if not self.verificarArchivosEnDir(): return
        
        if not len(self.modelo.listarLaves(True)):
            msje(self.vista,"¡No existen llaves privadas para firmar documentos!\n¡Debe crear o importar llaves privadas para realzar firmas de documentos!") 
            return 
        
        url = getUrl(self.vista)
        if not url: return
        if not msjOk(self.vista,u"Los archivos serán almacenados en: \n" + url + u"\n¿Está de acuerdo?"):
            return
        
        fingerPrintF, clave = self.vista.firmarDatos(self.vista)
        if not fingerPrintF or not clave: return 
                    
        error = False

        #Obtenemos el total de elementos añadidos al TreeCtrl que contiene los ficheros
        totalItemsTreeCtrl = self.vista.dirAnhadido.GetItemCount()
        #Procedemos a recorrer los archivos
        for i in range(totalItemsTreeCtrl):
            #Obtenemos la dirección de cada item del TreeCtrl
            pathOrigen = self.vista.dirAnhadido.GetItem(i,1).GetText()
            listaArchivos = self.obtenerArchivosAProcesar(pathOrigen).split(",")[0:-1]
            
            #Recorremos los archivos en contrados 
            for archivoProcesar in listaArchivos:
                
                f = open(archivoProcesar,'rb')
                data = f.read()
                f.close()
                
                data_procesada = self.firmar(data,fingerPrintF, clave)
                if not data_procesada:
                    msje(self.vista,"Ocurrio un error firmando el documento:\n" + archivoProcesar)
                    msgProceso = u"¡Es posible que algunos archivos no hayan sido firmados!\n¡Verifique en la ruta destino cuales fueron esos archivos!"
                    continue

                archivoCrear = self.obtenerArchivoACrear(archivoProcesar,pathOrigen,url)
                archivoCrear+= ".asc"

                if os.path.isfile(archivoCrear):
                    if not msjp(self.vista,u"Ya existe el archivo:\n%s\n¿Desea sobrescribirlo?" % archivoCrear.encode('utf-8')):
                        continue
                    else:
                        os.remove(archivoCrear)   
                else:
                    try:
                        os.makedirs(os.path.dirname(archivoCrear))
                    except OSError:
                        pass
                
                
                f = open(archivoCrear,"wb")
                f.write(data_procesada)
                f.close()

        #Limpiamos el TreeCtrl y el formulario
        self.vista.dirTree.ReCreateTree()
        self.limpiarDatosForm()
        msj = u"¡Los datos fueron procesados correctamente!"
        if error:
            msj = u"¡Solo fueron procesados los datos donde no ocurió error!"
        
        msja(self.vista,msj)
        
        
        
        
        
    
    def eventoVerificar(self,evt):
        
        if not self.verificarArchivosEnDir(): return
        
        if not len(self.modelo.listarLaves(False)):
            msje(self.vista,"¡No existen llaves públicas para verificar firmas!\n¡Debe crear o importar llaves públicas para verificar documentos!") 
            return 

        error = False
        msgProceso = ''

        #Obtenemos el total de elementos añadidos al TreeCtrl que contiene los ficheros
        totalItemsTreeCtrl = self.vista.dirAnhadido.GetItemCount()
        #Procedemos a recorrer los archivos
        
        for i in range(totalItemsTreeCtrl):
            #Obtenemos la dirección de cada item del TreeCtrl
            pathOrigen = self.vista.dirAnhadido.GetItem(i,1).GetText()
            listaArchivos = self.obtenerArchivosAProcesar(pathOrigen).split(",")[0:-1]            
            #Recorremos los archivos en contrados 
            for archivoProcesar in listaArchivos:
                
                f = open(archivoProcesar,'rb')
                data = f.read()
                f.close()
                
                data_procesada = self.verificar(data)
                msgProceso+= "\n--------------------------\n"
                msgProceso+= "Archivo: " + archivoProcesar
                msgProceso+= u"\nUsuario: " + str(data_procesada.username)
                msgProceso+= u"\nHuella digital: " + str(data_procesada.fingerprint)
                if data_procesada.valid:
                    msgProceso+= u"\nValidez: ¡Verificado!"
                else:
                    msgProceso+= u"\nValidez: ¡Firma inválida!" 
                            
                msgProceso+= "\n--------------------------\n"

        #Limpiamos el TreeCtrl y el formulario
        #self.vista.dirTree.ReCreateTree()
        self.limpiarDatosForm()
        msja(self.vista,msgProceso)

    
    def eventoCifrarFirmar(self,evt):
        
        if not self.verificarArchivosEnDir(): return

        url = getUrl(self.vista)
        if not url: return
        if not msjOk(self.vista,u"Los archivos serán almacenados en: \n" + url + u"\n¿Está de acuerdo?"):
            return
        
        
        if not len(self.modelo.listarLaves(False)):
            msje(self.vista,"¡No existen llaves públicas para cifrar documentos!\n¡Debe crear o importar llaves públicas para realizar el cifrado de documentos!") 
            return 
            
        if not len(self.modelo.listarLaves(True)):
            msje(self.vista,"¡No existen llaves privadas para firmar documentos!\n¡Debe crear o importar llaves privadas para realzar firmas de documentos!") 
            return 
        
        fingerPrintC = self.vista.cifrarDatos(self.vista)
        if not fingerPrintC: return
        
        fingerPrintF, clave = self.vista.firmarDatos(self.vista)
        if not fingerPrintF or not clave: return 

        error = False

        #Obtenemos el total de elementos añadidos al TreeCtrl que contiene los ficheros
        totalItemsTreeCtrl = self.vista.dirAnhadido.GetItemCount()
        #Procedemos a recorrer los archivos
        for i in range(totalItemsTreeCtrl):
            #Obtenemos la dirección de cada item del TreeCtrl
            pathOrigen = self.vista.dirAnhadido.GetItem(i,1).GetText()
            listaArchivos = self.obtenerArchivosAProcesar(pathOrigen).split(",")[0:-1]
            
            #Recorremos los archivos en contrados 
            for archivoProcesar in listaArchivos:
                f = open(archivoProcesar,'rb')
                data = f.read()
                f.close()

                data_procesada = self.cifrar(data,fingerPrintC,sign=fingerPrintF,passphrase=clave)
                if not data_procesada:
                    error = True
                    msje(self.vista,"Ocurrio un error al momento de querer cifrar y firmar el documento:\n" + archivoProcesar)
                
                archivoCrear = self.obtenerArchivoACrear(archivoProcesar,pathOrigen,url)
                archivoCrear+=".gpg"
                
                if os.path.isfile(archivoCrear):
                    if not msjp(self.vista,u"Ya existe el archivo:\n%s\n¿Desea sobrescribirlo?" % archivoCrear.encode('utf-8')):
                        continue
                    else:
                        os.remove(archivoCrear)   
                else:
                    try:
                        os.makedirs(os.path.dirname(archivoCrear))
                    except OSError:
                        pass
                
                
                f = open(archivoCrear,"wb")
                f.write(data_procesada)
                f.close()

        #Limpiamos el TreeCtrl y el formulario
        self.vista.dirTree.ReCreateTree()
        self.limpiarDatosForm()
        msj = u"¡Los datos fueron procesados!"
        if error:
            msj = u"¡Solo fueron procesados los datos donde no ocurió error!"
        
        msja(self.vista,msj)
    
    def eventoVerificarDesc(self,evt):
        
        if not self.verificarArchivosEnDir(): return
        
        if not len(self.modelo.listarLaves(True)):
            msje(self.vista,"¡No existen llaves privadas para descifrar documentos!\n¡Debe crear o importar llaves privadas para descifrar documentos!") 
            return
        
        if not len(self.modelo.listarLaves(False)):
            msje(self.vista,"¡No existen llaves públicas para cifrar documentos!\n¡Debe crear o importar llaves públicas para realizar el cifrado de documentos!") 
            return 
        
        url = getUrl(self.vista)
        if not url: return
        if not msjOk(self.vista,u"Los archivos serán almacenados en: \n" + url + u"\n¿Está de acuerdo?"):
            return
            
        clave = dialogEntrada(self.vista,"CLAVE PARA DESCIFRAR",True).encode('utf-8')
        if not clave: return

        

        error = False
        msgProceso = ''
        patron = re.compile("(\.gpg)$");

        #Obtenemos el total de elementos añadidos al TreeCtrl que contiene los ficheros
        totalItemsTreeCtrl = self.vista.dirAnhadido.GetItemCount()
        #Procedemos a recorrer los archivos
        for i in range(totalItemsTreeCtrl):
            #Obtenemos la dirección de cada item del TreeCtrl
            pathOrigen = self.vista.dirAnhadido.GetItem(i,1).GetText()
            listaArchivos = self.obtenerArchivosAProcesar(pathOrigen).split(",")[0:-1]
            
            #Recorremos los archivos en contrados 
            for archivoProcesar in listaArchivos:
                f = open(archivoProcesar,'rb')
                data = f.read()
                f.close()

                obj_data = self.descifrar(data,clave)
                data_procesada = obj_data.data
                if not data_procesada:
                    error = True
                    msje(self.vista,u"¡Error de descifrado!\n\n"
                                                    + u"Posibles causas:\n" 
                                                    + u"  1) No existe una llave privada para descifrar\n"
                                                    + u"  2) Ingreso de password incorrecto.\n\n"
                                                    + u"El fichero " + archivoProcesar + " no fue descifrado\n"
                                                    )
                    msgProceso = u'¡Fueron detectados errores con algunos archivos!'
                    continue
                                
                msgProceso+= "\n--------------------------\n"
                msgProceso+= "Archivo: " + archivoProcesar
                msgProceso+= u"\nUsuario: " + str(obj_data.username)
                msgProceso+= u"\nHuella digital: " + str(obj_data.fingerprint)
                if obj_data.valid:
                    msgProceso+= u"\nValidez: ¡Verificado!"
                else:
                    msgProceso+= u"\nValidez: ¡Firma inválida!"
                    msgProceso+= "\n--------------------------\n"
                
                archivoCrear = self.obtenerArchivoACrear(archivoProcesar,pathOrigen,url)
                archivoCrear = patron.sub("",archivoCrear)

                if os.path.isfile(archivoCrear):
                    if not msjp(self.vista,u"Ya existe el archivo:\n%s\n¿Desea sobrescribirlo?" % archivoCrear.encode('utf-8')):
                        continue
                    else:
                        os.remove(archivoCrear)   
                else:
                    try:
                        os.makedirs(os.path.dirname(archivoCrear))
                    except OSError:
                        pass
                
                
                f = open(archivoCrear,"wb")
                f.write(data_procesada)
                f.close()

        #Limpiamos el TreeCtrl y el formulario
        self.vista.dirTree.ReCreateTree()
        self.limpiarDatosForm()
        msj = u"¡Los datos fueron procesados!"
        if error:
            msj = u"¡Solo fueron procesados los datos donde no ocurió error!"
        
        msj+= "\n" + msgProceso
        
        msja(self.vista,msj)
        
        
    
    def eventoBorrarSeguro(self,evt):
        
        
        if not self.verificarArchivosEnDir(): return

        error = False
        mostrarEliminar = ''
        eliminar = []
        self.EJECUTADOS = 0
        
        #Obtenemos el total de elementos añadidos al TreeCtrl que contiene los ficheros
        totalItemsTreeCtrl = self.vista.dirAnhadido.GetItemCount()
        #Procedemos a recorrer los archivos
        for i in range(totalItemsTreeCtrl):
            
            #Obtenemos la dirección de cada item del TreeCtrl
            pathOrigen = self.vista.dirAnhadido.GetItem(i,1).GetText()
            listaArchivos = self.obtenerArchivosAProcesar(pathOrigen).split(",")[0:-1]
            
            mostrarEliminar+= pathOrigen + "\n"
            eliminar+= listaArchivos
            
            
        if not msjOk(self.vista,u"Los siguientes directorios y/o archivos serán borrados:\n" + mostrarEliminar.encode("utf8") + u"\n¿Está seguro de querer eliminar?"):
            return
        
        self.ARCHIVOS_ERROR = ''
        
        #for archivoProcesar in eliminar:
        #    if self.borrarSeguro(archivoProcesar):
        #        archivosError+= "%s\n" % archivoProcesar
        
        max = len(eliminar)
        self.worker = ThreadBorrarPapelera(self,max,eliminar)
            
            
        #Creamos el mensaje de borado de archivos
        dlg = wx.ProgressDialog("Barra de progreso","Borrando archivos",
                               maximum = max,
                               parent=self.vista,
                               style = wx.PD_CAN_ABORT
                                #wx.PD_APP_MODAL
                                #| wx.PD_ELAPSED_TIME
                                #| wx.PD_ESTIMATED_TIME
                                #| wx.PD_REMAINING_TIME
                                )
        keepGoing = True
        while self.EJECUTADOS < max and keepGoing:
            if self.EJECUTADOS == 0 and max > 1:
                ejecutados = 1
            else:
                ejecutados = self.EJECUTADOS
            
            
            (keepGoing, skip) = dlg.Update(ejecutados)
            
                
        dlg.Destroy()
        
        
        if not keepGoing:
            self.worker.abortar()
            msja(self.vista,u'¡Operación abortada!\nEs posible que algunos ficheros hayan sido barrados\n¡Como la operación fue cancelada no se elmininaron sus directorios!')
            #Limpiamos el TreeCtrl y el formulario
            self.vista.dirTree.ReCreateTree()
            self.limpiarDatosForm()
            return
            
        if self.ARCHIVOS_ERROR != '':
            msje(self.vista,u"#####################################\nERROR AL PROCESAR LOS ARCHIVOS:\n%s\n#####################################\n¡Los directorios no seran borrados!\nVerifique que tenga permisos para borrar" % self.ARCHIVOS_ERROR)#archivosError
            #Limpiamos el TreeCtrl y el formulario
            self.vista.dirTree.ReCreateTree()
            self.limpiarDatosForm()
            return
            
                        
        #Procedemos a eliminar los directorios ya que shred no borra directorios
        for pathOrig in mostrarEliminar.split('\n')[0:-1]:
            if os.path.isdir(pathOrig):
                rmtree(pathOrig)
                
        #Limpiamos el TreeCtrl y el formulario
        self.vista.dirTree.ReCreateTree()
        self.limpiarDatosForm()
        
        msja(self.vista,u"¡Los directorios y/o archivos fueron eliminados correctamente!")
    
    ##############################    
    
    def habilitarDesmontarUnidad(self,valor):
        
        self.vista.parent.tb.EnableTool(self.vista.idDesmontarUnidad,valor)
    
    def habilitarEliminarUnidad(self,valor):
        
        self.vista.parent.tb.EnableTool(self.vista.idEliminarUnidad,valor)
    
    def verificarExisteRuta(self):
        
        if not os.path.isdir(self.rutaTibisay + self.unidades):
            if msjp(self.vista.ventanaHija,"La ruta " + self.rutaTibisay + self.unidades + " no existe. Para poder continuar con la ejecución debe crear el directorio. ¿Desea crear el directorio?"):
                try:
                    os.makedirs(self.rutaTibisay + self.unidades)
                except:
                    msja(self.vista,"Error al momento de querer crear el directorio %s . El sistema operativo arrojó el sigueinte error: %s" % (self.rutaTibisay + self.unidades,str(sys.exc_info()[1])))
            
                    return False
            else:
                return False
        elif not os.path.isdir(self.rutaTibisay + self.montaje):
            if msjp(self.vista.ventanaHija,"La ruta " + self.rutaTibisay + self.montaje + " no existe. Para poder continuar con la ejecución debe crear el directorio. ¿Desea crear el directorio?"):
                try:
                    os.makedirs(self.rutaTibisay + self.montaje)
                except:
                    msja(self.vista,"Error al momento de querer crear el directorio %s . El sistema operativo arrojó el sigueinte error: %s" % (self.rutaTibisay + self.montaje,str(sys.exc_info()[1])))
            
                    return False
            else:
                return False
            
        return True
    
    
    def verificarExisteUnidad(self,nombre):
        
        if os.path.isdir('%s%s/%s' % (self.rutaTibisay,self.unidades,nombre)):
            msje(self.vista.ventanaHija,"Ya existe una unidad con el nombre: %s " % nombre)
            return True
            
        return False
    
    def crearUnidad(self,nombre,clave,confirmacion):
        
        if nombre.GetValue() == "":
            msja(self.vista.ventanaHija,"Debe ingresar el nombre de la unidad")
            nombre.SetFocus()
        elif clave.GetValue() == "":
            
            msja(self.vista.ventanaHija,"Debe ingresar una clave")
            clave.SetFocus()
        elif confirmacion.GetValue() == "":
            msja(self.vista.ventanaHija,"Debe ingresar la confiramción de la clave")
            confirmacion.SetFocus()
        elif clave.GetValue() != confirmacion.GetValue():
            msje(self.vista.ventanaHija,"La clave y la confirmación no son iguales. Ingreselas de nuevo")
            clave.SetFocus()
        else:
            
            
            #Verificamos que exita la ruta donde se almacenan las unidades
            if not self.verificarExisteRuta():
               return
        
            #Verificamos si ya existe una unidad con ese nombre
            if self.verificarExisteUnidad(nombre.GetValue()):
               return
           
            #Verificamos que hayan permisos de escritura en la carpeta
            
            
            #Verificamos que el nombre sea un campo válido para nombre
            nomVal = validarNombreFichero(nombre.GetValue())
            claveVal = validarClave(clave.GetValue())
            if not nomVal:
                msje(self.vista.ventanaHija,"¡El nombre de la unidad no es válido!")
            #Verificamos que la clave sea un campo valido de clave
            if not claveVal:
                msje(self.vista.ventanaHija,"¡La clave tiene un formato que no es válido!")
            
            if nomVal and claveVal:
                flag = self.modelo.crearUnidad(nombre.GetValue(),clave.GetValue())
                if flag:
                    self.vista.ventanaHija.parent.txtPanelC.SetLabel("Creando y montando la unidad " + nombre.GetValue())
                    msja(self.vista.ventanaHija,"La unidad " + nombre.GetValue() + " fue creada existosamente")
                    self.vista.ventanaHija.cerrarVentana(0)
                    self.vista.ventanaHija = None
                    
                    index = self.vista.listUnidades.InsertImageStringItem(sys.maxint,nombre.GetValue(),self.vista.directorio)
                    self.vista.listUnidades.SetItemData(index,0)
                    self.vista.listUnidades.SetStringItem(index, 1, "Montada")
                    
                    #Procedemos a abrir nautilus con la unidad montada
                    #print 'nautilus "%s%s/%s"' % (self.rutaTibisay,self.montaje,nombre.GetValue())
                    os.system('nautilus "%s%s/%s"' % (self.rutaTibisay,self.montaje,nombre.GetValue()))
                
                else:
                    msje(self.vista.ventanaHija,"¡Error! No se pudo crear la base de datos")
        
    
    
    def listarUnidades(self):
    
        
        self.verificarExisteRuta()
        #Buscamos las unidades que se encuentran en el directorio unidades
        ruta = self.rutaTibisay + self.unidades
        unidades = [f.split(".")[0] for f in os.listdir(ruta) if os.path.isdir(os.path.join(ruta, f))]

        for u in unidades:
            index = self.vista.listUnidades.InsertImageStringItem(sys.maxint,u,self.vista.directorio)
            self.vista.listUnidades.SetItemData(index,0)
            self.vista.listUnidades.SetStringItem(index, 1, "Desmontada")

    def eliminarUnidad(self):
        
        unidad = self.vista.tree.GetItemText(self.vista.treeSeleccionado)
        
        #Verificamos que se desee eliminar la unidad
        if not msjp(self.vista.ventanaHija,u"¿Está seguro de querer eliminar la unidad?"):
            return
        
        #Verificar si la unidad está monmtada
        if self.unidadMontada(unidad):
            #Procedemos a desmontarlar
            #print "Unidad montada"
            self.modelo.desmontarUnidad(unidad)
        
        if not self.modelo.eliminarUnidad(unidad):
            msje(self.vista.ventanaHija,"¡Error al momento de querer eliminar la unidad!\n¡Consulte con el administrador del sistema!")
        
        
        #self.vista.tree.Delete(self.vista.treeSeleccionado)
        #self.habilitarDesmontarUnidad(False)
        #self.habilitarEliminarUnidad(False)
        self.entrarEvento = False
        self.listarUnidades()
    
    def cambiarLabelItemUnidad(self,label):
       
        #print self.vista.listUnidades.GetItemText(self.vista.itemListeleccionado)
        #item = self.vista.listUnidades.GetItem(self.vista.itemListeleccionado, 1) 
        #print item.GetText()
        #print self.vista.listUnidades.GetSelectedItemCount()
        if self.vista.itemListeleccionado != None:
            self.vista.listUnidades.SetStringItem(self.vista.itemListeleccionado, 1, label)
        else:
            print 'No hay una unidad seleccionada'
        
        
    
    #Verifica si una unidad ya se encuentra montada    
    def unidadMontada(self,unidad):
        
        flag = False
        fTmp = '/tmp/tmpUnidadMontada.tibisay'
        os.system('df | grep -e "%s%s/%s" > %s' % (self.rutaTibisay,self.montaje,unidad,fTmp))
        f = open(fTmp,"r")
        lon = len(f.readlines())
        if lon > 0:
            flag = True
        
        f.close()
        os.remove(fTmp)
        return flag   
        
            
    
    def verificarMontarUnidad(self,FrameMontarUnidad):
        
        #Verificamos que se haya selccionado una unidad para montar
        if not self.vista.itemListeleccionado != None:
            msja(self.vista,"Debe seleccionar una unidad para luego montarlar")            
            return
        
        #Hacemos el llamado al formulario que permite que se ingrese la clave
        #self.parent.listUnidades.GetItemText(self.parent.itemListeleccionado)
        #cmd = "encfs --extpass='zenity --entry --hide-text --title=\"Password\" --text=\"Please enter your password to mount DropboxEncrypted.\"' /home/joger/.tibisay/unidades/Documentos/ /home/joger/.tibisay/montaje/Documentos"
        #os.system('%s' % cmd)
        
        win = FrameMontarUnidad(self.vista, -1, "Montar Unidad", size=(270, 170),
                  style = wx.DEFAULT_FRAME_STYLE)
        
        win.Show(True)
        self.vista.parent.Enable(False)
        

    def montarUnidad(self,lUnidad,iClave):

        unidad = lUnidad.GetLabelText()
        clave = iClave.GetValue()
        
        if clave == "":
            msja(self.vista.ventanaHija,"Debe ingresar una clave")
        else:
            #Verificamos si existe la carpeta tibisay
        
            #Verificamos si existe la base de datos
        
            #Verificamos que hayan permisos de escritura en la carpeta

            #Verificamos que la unidad ya no esté montada
            if self.unidadMontada(unidad):
                msja(self.vista.ventanaHija,"La unidad ya se encuentra montada")
                return
            
            
            
            if self.modelo.montarUnidad(unidad, clave):
                #Procedemos a cambair el estado del listctrl
                self.cambiarLabelItemUnidad("Montada")
                #Procedemos a abrir nautilus
                #print self.rutaTibisay,self.montaje,unidad
                os.system('nautilus "%s%s/%s"' % (self.rutaTibisay,self.montaje,unidad))
            else:
                return

            self.vista.ventanaHija.cerrarVentana(0)
  
    
    def verUnidad(self):
        if self.vista.itemListeleccionado != None:
            unidad = self.vista.listUnidades.GetItemText(self.vista.itemListeleccionado)
            if self.unidadMontada(unidad):
                os.system('nautilus "%s%s/%s"' % (self.rutaTibisay,self.montaje,unidad))
            else:
                msja(self.vista,"La unidad debe estar montada para poder verla")
        else:
            msja(self.vista,"Debe seleccionar la unidad que desea ver")

    def desmontarUnidad(self):

        #Verificamos la existencia de un item seleccionado
        #print self.vista.itemListeleccionado != None
        if self.vista.itemListeleccionado != None:
            unidad = self.vista.listUnidades.GetItemText(self.vista.itemListeleccionado)
            if self.unidadMontada(unidad):
                if self.modelo.desmontarUnidad(unidad):
                    self.cambiarLabelItemUnidad("Desmontada")
                    msja(self.vista,"La unidad ha sido desmontada")
            else:
                msja(self.vista,"La unidad no se encuentra montada")
        else:
            msja(self.vista,'No hay una unidad seleccionada')
    
    def enviarArchivos(self):
        #tree = self.vista.dirTree.GetTreeCtrl()
        #treeitem = tree.GetSelection()
        #print treeitem     
        parentPath = self.vista.dirTree.GetPath()
        nombreElemento = parentPath.split("/")[-1]
        if os.path.isdir(parentPath):
            img = self.vista.directorio
        else: 
            img = self.vista.archivo
        """
        else:
            img = self.vista.imgPapelera
            parentPath = os.getenv('HOME') + "/.local/share/Trash/files/*"
            tree = self.vista.dirTree.GetTreeCtrl()
            nombreElemento = tree.GetItemText(tree.GetLastChild(tree.GetRootItem()))
        """    
            

        index = self.vista.dirAnhadido.InsertImageStringItem(sys.maxint,nombreElemento,img)
        self.vista.dirAnhadido.SetStringItem(index, 1,parentPath)
        self.vista.dirAnhadido.SetItemData(index,0)
        self.vista.dirAnhadido.SetItemData(index,1)

    def borrarPapelera(self,parent):
        
        if msjp(self.vista,"¿Esta seguro de querer eliminar los datos de la papelera de forma permanente del sistema?"):
            self.EJECUTADOS = 0
            rutaPapelera = os.getenv('HOME') + '/.local/share/Trash/files/'
            listaArchivos = self.obtenerArchivosAProcesar(rutaPapelera).split(",")[0:-1]
            
            self.ARCHIVOS_ERROR = ''
            max =  len(listaArchivos)
            
            self.worker = ThreadBorrarPapelera(self,max,listaArchivos)
            
            #Creamos el mensaje de borado de archivos
            dlg = wx.ProgressDialog("Barra de progreso","Borrando archivos",
                               maximum = max,
                               parent=self.vista,
                               style = wx.PD_CAN_ABORT
                                #wx.PD_APP_MODAL
                                #| wx.PD_ELAPSED_TIME
                                #| wx.PD_ESTIMATED_TIME
                                #| wx.PD_REMAINING_TIME
                                )
            keepGoing = True
            #ejecutado = 0
            while self.EJECUTADOS < max and keepGoing:
                
                if self.EJECUTADOS == 0:
                    ejecutados = 1
                else:
                    ejecutados = self.EJECUTADOS
                    
                
                (keepGoing, skip) = dlg.Update(ejecutados)
                
            dlg.Destroy()
            
            #Borramos los directorios de la papelera
            if not keepGoing:
                self.worker.abortar()
                self.resultado = u'¡Operación abortada!'
                return self.resultado
                
            if self.ARCHIVOS_ERROR != '':
                self.resultado = u"¡Error al procesar el/los archivo(s):\n%s!\n¡Los directorios no seran borrados!\n¡Verifique que tenga permisos para eliminar los archivos!" % self.ARCHIVOS_ERROR
                return self.resultado
                
            
            
            try:
                rmtree(rutaPapelera)
            except OSError:
                pass
            
                                
            self.resultado = u'¡Los archivos fueron eliminados exitosamente!'
            return self.resultado
            
        return u"¡La pepelera no fue borrada!"    
 
    def eliminarArchivos(self):
        
        if self.vista.itemDirAnhadido != None:
            self.vista.dirAnhadido.DeleteItem(self.vista.itemDirAnhadido)
            self.vista.itemDirAnhadido = None

    

    def verificarCampoGuardar(self,campo):
            if campo == '':
                msja(self.vista,"Debe ingresar la ruta donde se almacenaran los datos procesados")
                self.vista.iGuardar.SetFocus()
                return False
            elif not os.path.isdir(campo):
                msja(self.vista,"La ruta seleccionada para almacenar los datos no es una ruta válida")
                self.vista.iGuardar.SetFocus()
                return False
           
            #QUE PENDEINTE VERIFICAR SI HAY PERMISOS DE ESCRITURA                

            return True

    
    def verificarArchivosEnDir(self):
        if self.vista.dirAnhadido.GetItemCount():
            return True
        else:
            msja(self.vista,"Debe añadir directorios y/o ficheros para se procesados")
            return False
            
            
    def cifrar(self,data,fingerPrintC,always_trust=True,sign=None,passphrase=None):#fingerPrintF=None
        
        #datos = self.modelo.gpg.encrypt(data,correo,always_trust=True)
        datos = self.modelo.gpg.encrypt(data,fingerPrintC,always_trust=always_trust,sign=sign,passphrase=passphrase)#firmante = fingerPrintF
        return datos.data
        
        
    def firmar(self,data,fingerprint,clave):
        
        datos = self.modelo.gpg.sign(data,keyid=fingerprint,passphrase=clave)
        if datos.data:
            return datos.data
        else:
            return False

        
    def realizarFirma(self):
        
        if self.verificarArchivosEnDir():
            msja(self.vista,"Seleccione el directorio para almacenar")
            url = getUrl(self.vista)
            if msjOk(self.vista,u"Los archivos serán almacenados en: \n" + url + u"\n¿Está de acuerdo?"):
                self.firmar(url)
        else:
            msja(self.vista,"Debe añadir directorios y/o ficheros para se procesados")
            
    
    def borrarSeguro(self,path):
        
        r = os.system('shred "%s"' % path)
        if r > 0:
            return True
        
        try:
            os.remove(path)
        except OSError:
            return True
        
        return False
        
        

    def buscarLlavePrivada(self,id):
        
        public_keys = gpg.list_keys(True)
        for pk in public_keys:
            if pk['uids'].find(id):
                return True
        
        return False
    
    def descifrar(self,datos,clave):
        
        return self.modelo.gpg.decrypt(datos,passphrase=clave,always_trust=True)
        

    def verificar(self,data):

        firma = self.modelo.gpg.verify(data)
        #print firma.valid
        return firma
        
    def limpiarDatosForm(self):

        #self.vista.radio = self.vista.radio1
        #self.radioSeleccionado()
        self.vista.dirAnhadido.DeleteAllItems()
        #self.vista.iGuardar.SetValue("")

    def obtenerArchivosCrear(self,listaFicheros,pathOrigen,rutaDestino):
        ficheros = []
        if os.path.isdir(pathOrigen): 
            #Validamos que las rutas vengan si la / al final de ellas
            if pathOrigen[-1] == "/":
                pathOrigen = pathOrigen[0:-1]
            if rutaDestino[-1] == "/":
                rutaDestino == rutaDestino[0:-1]

            for l in listaFicheros:
                ficheros.append(re.sub(pathOrigen + '/',rutaDestino + '/',l))

        else:
            #Si la ruta origen es un archivo y no un directorio lo debemos tratar diferente
            nuevoOrigen = ''
            for o in pathOrigen.split('/')[1:-1]:
                nuevoOrigen+= '/' + o

            #print nuevoOrigen,rutaDestino, pathOrigen  
            ficheros.append(re.sub(nuevoOrigen + '/',rutaDestino + '/',pathOrigen))

        return ficheros

    def obtenerDirACrear(self,listaFicheros,pathOrigen,rutaDestino):
        urls = []
        if os.path.isdir(pathOrigen):
            #Validamos que las rutas vengan si la / al final de ellas
            if pathOrigen[-1] == "/":
                pathOrigen = pathOrigen[0:-1]
            if rutaDestino[-1] == "/":
                rutaDestino == rutaDestino[0:-1]
            for x in listaFicheros:
                url = ''
                for r in x.split('/')[0:-1]:
                    url+= '%s/' % r
                    
                if url != '':
                    try:
                        url = re.sub(pathOrigen + '/',rutaDestino + '/',url)
                        urls.index(url)
                    except ValueError:
                        urls.append(url)
        
        return urls

    #Retorna un string con todos los archivos y sus respectivos directorios separados por ","
    def obtenerArchivosAProcesar(self,path):
        archivos = ''
        if os.path.isdir(path):
            if path[-1] == "/":
                path = path[0:-1]
            #Aqui vamos a listar el contenido del directorio
            lista = []
            try:
                lista = os.listdir(path)
            except OSError:
                pass
                
            #Recorremos el contenido del directorio y creamos la recursividad
            for valor in lista:
                d = self.obtenerArchivosAProcesar(os.path.join(path,valor))
                if d != None or d != '':
                    archivos+= d
                            
            return archivos 
        else:# os.path.isfile(path):
            return path + ','

    def obtenerArchivoACrear(self,archivoProcesar,pathOrigen,url):
        
        if os.path.isdir(pathOrigen): 
        
            nombreDirectorio = pathOrigen.split('/')[-1]
            archivoCrear = re.sub(pathOrigen,"",archivoProcesar)
            return os.path.join(url,nombreDirectorio,archivoCrear[1:])
        #Si la ruta origen es un archivo y no un directorio lo debemos tratar diferente
        else:
            nombreArchivo = archivoProcesar.split('/')[-1]
            return os.path.join(url,nombreArchivo)
    
    def crearDirectorios(self,dirCrear):

        for d in dirCrear:
            try:
                os.makedirs(d)
            except OSError:
                pass
            except:
                msje(self.vista,'Error al momento de crear los directorios: ' + str(sys.exc_info()[1]))
                return False
            
        return True   
            
    """
    def borrarDirectorios(self,dirABorrar,rutaDestino):    
        for ca in dirABorrar:
            if ca != (rutaDestino + '/'):
                try:
                    print 'Borrando el directorio creado %s ' % ca
                    #rmtree(ca)
                except OSError:
                    pass
                except:
                    msjr(self.vista,'Error al momento de crear los directorios: ' + str(sys.exc_info()[1]))
                    return False

    """
    
    def listdirs(self,folder):
        try:
            directorios = [d for d in os.listdir(folder) if os.path.isdir(os.path.join(folder, d)) and d[0] != "."]
            archivos = [f for f in os.listdir(folder) if os.path.isfile(os.path.join(folder, f)) and f[0] != "."]
            return directorios,archivos,True
        except OSError:
            self.AbrirMensajeError("¡Error de url!")
            return {},{},False

    def crearLlaves(self,iNombre,
        iCorreo,
        iClave,
        iConfirmacion,
        iTipo,
        iLongitud,
        iComentario,
        fechaCalendario):

        #Creamos las variables
        """
        nombre = iNombre.GetValue()
        correo = iCorreo.GetValue()
        clave = iClave.GetValue()
        confirmacion = iConfirmacion.GetValue()
        tipo = iTipo.GetValue()
        longitud = iLongitud.GetValue()
        comentario = iComentario.GetValue()
        fecha = fechaCalendario.GetValue()
        """

        #Validamos que no esten vacias
        if iNombre.GetValue() == "":
            msja(self.vista.ventanaHija,"Debe ingresar un nombre asociado a las llaves")
            iNombre.SetFocus()

        elif not verificarCorreo(iCorreo.GetValue()):
            msja(self.vista.ventanaHija,"El formato del correo no es válido")
            iCorreo.SetFocus()

        elif not validarClave(iClave.GetValue()):
            msja(self.vista.ventanaHija,"El formato de la clave no es válido")
            iClave.SetFocus()

        elif iConfirmacion.GetValue() != iConfirmacion.GetValue():
            msja(self.vista.ventanaHija,"La clave no coicide con la confirmación")
            iClave.SetFocus()

        elif fechaCalendario.GetValue() == "":
            msja(self.vista.ventanaHija,"Debe ingresar una fecha")
            fechaCalendario.SetFocus()

        else:  

            if iTipo.GetStringSelection() == 'DSA':
                subTipo = 'ELG-E'
            elif iTipo.GetStringSelection() == 'RSA':
                subTipo = 'RSA'
            else:
                msja(self.vista.ventanaHija,"Error en el tipo. Los posibles valores son: DSA o RSA")
                return
            
         
            msja(self.vista.ventanaHija,u"Para generar el par de llaves es necesario:\n"
                                                    + u"\n1) Reproducir música"
                                                    + u"\n2) Reproducir videos"
                                                    + u"\n3) Abrir y cerrar ventanas"
                                                    + u"\n4) Realizar cambios de escritorio"
                                                    + u"\n5) Abrir muchas pestañas con páginas en FireFox"
                                                    + u"\n\nGenerar las llaves toma algo de tiempo, por favor sea paciente")
            
            if self.modelo.crearLlaves(iNombre.GetValue(),
                   iCorreo.GetValue(),
                   iClave.GetValue(),
                   iTipo.GetStringSelection(),
                   iLongitud.GetStringSelection(),
                   iComentario.GetValue(),
                   subTipo,
                   fechaCalendario.GetValue()):

                msja(self.vista.ventanaHija,"El par de llaves fue creado existosamente")
                self.vista.ventanaHija.cerrarVentana(0)
            else:
                msja(self.vista.ventanaHija,u"¡Ocurrió un error al momento de querer crear las llaves\n¡Consulte con el administrador del sistema!")

          
    def importarLlaves(self,iArchivo):

        if iArchivo.GetValue() == "":
            msja(self.vista.ventanaHija,"Debe seleccionar el archivo que desea importar")
        else:
         
            try:
                f = open(iArchivo.GetValue(),"r")
                import_result = self.modelo.gpg.import_keys(f.read())
                f.close()
            except IOError:
                msja(self.vista.ventanaHija,"Error con el archivo: " + str(sys.exc_info()[1]))
                return
            except:
                msja(self.vista.ventanaHija,"Error en la importacion: " + str(sys.exc_info()[1]))
                return
                
                
            if import_result.count == 0 or None:
                msja(self.vista.ventanaHija,"No se realizó ninguna importación. Verifique que el archivo no está corrupto")
            else:
                msja(self.vista.ventanaHija,"El número de importaciones fue: %s" % import_result.count) 
                self.vista.ventanaHija.cerrarVentana(0)


    def exportarLlaves(self,iGuardarEn,iCorreo,iLlave):

        if not verificarCorreo(iCorreo.GetValue()):
            msja(self.vista.ventanaHija,"Formato de correo no válido")
        elif iGuardarEn.GetValue() == "":
            msja(self.vista.ventanaHija,"Debe seleccionar la ruta donde va a almacenar la exportación")
        else:
            if iLlave.GetStringSelection() == 'Publica':
                tipo = 0
            elif iLlave.GetStringSelection() == 'Privada':
                tipo = 1
            elif iLlave.GetStringSelection() == 'Ambas':
                tipo = 2

            
            if os.path.isfile(iGuardarEn.GetValue()):
                if not msjp(self.vista.ventanaHija,"El archivo ya existe ¿Desea rescribirlo?"):
                    return
            try:
                f = open(iGuardarEn.GetValue(),"w")    
            except IOError:
                msja(self.vista.ventanaHija,"Error con el archivo: " + str(sys.exc_info()[1]))
                return
            except:
                msja(self.vista.ventanaHija,"Error desconocido: " + str(sys.exc_info()[1]))
                return

            msj = 'Resultados exportación:'
            if tipo == 2 or tipo == 0:
                llavesPublicas = self.modelo.gpg.export_keys(iCorreo.GetValue())
                if llavesPublicas:
                    msj+= '\n\tLlave Publica: Exportada'
                    f.write(llavesPublicas + '\n')
                else:
                    msj+= '\n\tLlave Publica: NO Exportada'
            
            if tipo == 2 or tipo == 1:
                llavesPrivadas = self.modelo.gpg.export_keys(iCorreo.GetValue(),True)
                if llavesPrivadas:
                    msj+= '\n\tLlave Privada: Exportada'
                    f.write(llavesPrivadas + '\n')
                else:
                    msj+= '\n\tLlave Privada: NO Exportada'

            f.close()            
            msja(self.vista.ventanaHija,msj)
            self.vista.ventanaHija.cerrarVentana(0)
            
    def eliminarLlaves(self,listaLlaves,tipo):
        
        for l in listaLlaves:
            #Una llave publica no puede ser borrada sin que se haya borrado la privada. Esa es la razón por la que siempre
            #borro la llave privada
            obj = self.modelo.gpg.delete_keys(l,True)
            if tipo == "Publicas":
                obj = self.modelo.gpg.delete_keys(l)
        
        return True


    def cargarLlaves(self,parent,ctrlList,seleccion):
        
        
        ctrlList.DeleteAllItems()    
        keys = []
        if seleccion == 1:
            keys = self.modelo.gpg.list_keys(False)
            
        elif seleccion == 2:
            keys = self.modelo.gpg.list_keys(True)
            
            
        for l in keys:
            index = ctrlList.InsertStringItem(sys.maxint,l['fingerprint'])
            ctrlList.SetStringItem(index, 1, l['uids'][1].encode("utf8"))
            creacion = ''
            separador = "-"
            try:
                #creacion = separador.join([str(x) for x in list(time.gmtime(float())[0:3])])
                creacion = separador.join([str(x) for x in list(time.gmtime(float(l['date']))[0:3])])
                
            except:
                pass
            
            expira = ''
            try:
                expira = separador.join([str(x) for x in list(time.gmtime(float(l['expires']))[0:3])])
            except:
                pass
                
            ctrlList.SetStringItem(index, 2,creacion)
            ctrlList.SetStringItem(index, 3, expira)
            ctrlList.SetItemData(index, 0)
    
    #Esta funcion la uso para poder controlar cuando el thread termina su labor
    #def EVT_RESULT(self,func):
    #    self.vista.Connect(-1, -1, EVT_RESULT_ID, func)
    
    #def resultadoThread(self, event):
        
        """
        if event.data is None:
            # Thread aborted (using our convention of None return)
            self.status.SetLabel('Computation aborted')
        else:
            # Process results here
            self.status.SetLabel('Computation Result: %s' % event.data)
        # In either event, the worker is done
        """
        #print event.data
    #    self.resultado = event.data
        #print self.resultado
    #    self.worker = None
        
        

class ThreadBorrarPapelera(Thread):

    def __init__(self, controlador,max,listaArchivos):

        Thread.__init__(self)
        self._controlador = controlador
        self._abortar = 0
        self.max = max
        self.listaArchivos = listaArchivos
        self.start()

    def run(self):
        #Proceso Thread que se encargará de borrar la papelera
        #ejecutado = 0
        for i in range(self.max):
            if os.path.isfile(self.listaArchivos[i]):
                
                error_borrar = self._controlador.borrarSeguro(self.listaArchivos[i])
                if error_borrar:
                    self._controlador.ARCHIVOS_ERROR += "%s\n" % self.listaArchivos[i]
                    
                
                self._controlador.EJECUTADOS+=1
                #print self._controlador.EJECUTADOS
                if self._abortar:
                    #wx.PostEvent(self._controlador.vista, ResultEvent("Operación abortada"))
                    return
                
            
            
        #wx.PostEvent(self._controlador.vista, ResultEvent('Operación abortadaLos archivos fueron eliminados exitosamente!'))

    def abortar(self):

        # Method for use by main thread to signal an abort
        self._abortar = 1

##Clase que alamcenar el rusultado obtenido
"""
class ResultEvent(wx.PyEvent):

    def __init__(self, data):

        wx.PyEvent.__init__(self)
        self.SetEventType(EVT_RESULT_ID)
        self.data = data
"""
